﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BreukTrainer.BreukModel
{
    public delegate Breuk DelegateBreukenBewerking(Breuk b1, Breuk b2);

    /// <summary>
    /// Erft over van <see cref="BreukContainer"/>. Voor alle bewerkingen op Breuken welke een nieuwe <see cref="Breuk"/> opleveren.
    /// </summary>
    /// <remarks>
    /// Door gebruik te maken van delegates kunnen we aan deze klasse allerlei methodes 
    /// die in de klasse Breuk uitgewerkt zijn en die op 2 breuken een bewerking doen 
    /// (optellen, delen, maximum berekenen, ..) die een nieuwe breuk oplevert doorgeven.
    /// Deze klasse hoeft niet te weten welke bewerkingsmethodes er in <see cref="Breuk"/> bestaan.
    /// </remarks>
    public class ProgrammeerbareBreukContainer: BreukContainer
    {
        

        /// <summary>
        /// Voert de bewerking in <paramref name="functie"/> uit op alle Breuken in <see cref="BreukContainer"/>.
        /// </summary>
        /// <param name="functie">De <see cref="DelegateBreukenBewerking"/> met een verwijzing naar een bewerking uit <see cref="Breuk"/></param>
        /// <returns><see cref="Breuk"/></returns>
        public Breuk DoeBewerking(DelegateBreukenBewerking functie)
        {
            return DoeBewerking(functie, Breuken.Count);
        }

        /// <summary>
        /// Voert de bewerking in <paramref name="functie"/> uit op een aantal Breuken in <see cref="BreukContainer"/>.
        /// </summary>
        /// <param name="functie">De <see cref="DelegateBreukenBewerking"/> met een verwijzing naar een bewerking uit <see cref="Breuk"/></param>
        /// <param name="aantal">Een <see langword="integer"/>: het aantal Breuken aan het begin van <see cref="BreukContainer"/>.</param>
        /// <returns><see cref="Breuk"/></returns>
        /// <remarks>Als <paramref name="aantal"/> groter is als aantal breuken in <see cref="BreukContainer"/> worden zelfde breuken hergebruikt.</remarks>
        public Breuk DoeBewerking(DelegateBreukenBewerking functie, int aantal)
        {
            Breuk br = new Breuk(Breuken[0].Teller, Breuken[0].Noemer);
            for (int i = 1; i < aantal; i++)
            {
                br = functie(br, Get(i));
                if (i == Breuken.Count)//mogelijks ook met dubbele for-lus.
                {
                    aantal -= i;
                    i = 0;
                }
            }
            return br;
        }

        /// <summary>
        /// Voert meerdere bewerkingen uit en geeft de formule terug.
        /// </summary>
        /// <param name="functies">Een <see langword="array"/> van <see cref="DelegateBreukenBewerking"/>.</param>
        /// <param name="operanden">Een <see langword="array"/> van <see langword="string"/> operanden.</param>
        /// <returns><see langword="string"/>: de formule.</returns>
        /// <remarks>Kan nog ingewikkelder: ipv van links naar rechts te rekenen, 
        /// rekening houden met volgorde bewerkingen (*&/ eerst).</remarks>
        public String DoeBewerking(DelegateBreukenBewerking[] functies, params string[] operanden)
        {
            if (functies.Length != operanden.Length) return null;
            Breuk br = new Breuk(Breuken[0].Teller, Breuken[0].Noemer);
            String formule = br.ToString();
            int length = functies.Length;
            for(int i = 0; i < length; i++)
            {
                formule += " " + operanden[i] + " " + Breuken[i+1].ToString();
                br = functies[i](br, Breuken[i+1]);
            }
            formule += "=" + br.Vereenvoudig().ToString();
            return formule;
        }
        /// <summary>
        /// Voert meerdere bewerkingen uit en geeft de oplossing terug.
        /// </summary>
        /// <param name="functies">Een <see langword="array"/> van <see cref="DelegateBreukenBewerking"/>.</param>
        /// <param name="operanden">Een <see langword="array"/> van <see langword="string"/> operanden.</param>
        /// <returns><see langword="string"/>: de oplossing.</returns>
        /// <remarks>Kan nog ingewikkelder: ipv van links naar rechts te rekenen, 
        /// rekening houden met volgorde bewerkingen (*&/ eerst).</remarks>
        public String DoeBewerkingResult(DelegateBreukenBewerking[] functies, params string[] operanden)
        {
            //hier mss nog een extra controle ivm aantal functies
            if (functies.Length != operanden.Length) return null;
            Breuk br = new Breuk(Breuken[0].Teller, Breuken[0].Noemer);
            int length = functies.Length;
            for (int i = 0; i < length; i++)
            {
                br = functies[i](br, Breuken[i + 1]);
            }
            return br.Vereenvoudig().ToString();
        }
    }
}
